﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace LinkShareWpf.Commands
{

    // L'interfaccia ICommand definisce un comando. Essa è formata da tre membri:
    // i due metodi CanExecute ed Execute
    // e l'evento CanExecuteChanged.

    // Il metodo CanExecute restituisce un valore booleano che indica l'effettiva disponibilità del comando
    // Il metodo Execute definisce il metodo da invocare allorquando viene eseguito il comando
    // L'evento CanExecuteChanged è scatenato all'occorrenza di cambiamenti che influenzano l'abilitazione del comando

    public class DelegateCommand : ICommand
    {

        // Il delegate Action, predefinito in .Net, rappresenta un metodo
        // con un numero di parametri in ingresso variabile da 0 a 16
        // e privo di valore di ritorno
        private readonly Action<object> executeMethod = null;

        // Il delegate Predicate, predefinito in .Net, è usato per incapsulare un metodo
        // con un singolo parametro in ingresso
        // e un valore di ritorno booleano
        private readonly Predicate<object> canExecuteMethod = null;

        // Questo evento serve a gestire i cambiamenti nell'abilitazione dei comandi
        // All'occorrenza di questo evento, la sorgente del comando invoca il metodo CanExecute:
        // se il valore restituito è false, la sorgente del comando si disabilita
        public event EventHandler CanExecuteChanged
        {
            add
            {
                // La classe CommandManager fornisce metodi di utilità correlati ai comandi.
                // L'evento RequerySuggested viene scatenato ogniqualvolta vengono individuate delle condizioni
                // che potrebbero cambiare l'abilitazione di un comando:
                // esso informa la sorgente di un comando
                // di interrogare il comando a cui è associata
                // per determinare se esso possa essere eseguito o meno.
                // Registrandoci a questo evento facciamo in modo che il valore di ritorno del metodo CanExecute
                // venga ricalcolato opportunamente in seguito a un cambiamento di focus,
                // a un input da parte dell'utente, e così via...
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        // Con questa generica implementazione di ICommand, che accetta nel costruttore un Action ed un Predicate,
        // abbiamo la possibilita di creare istanze di tipo DelegateCommand
        // e mapparle a dei gestori ad hoc in base alle funzionalità che quel comando deve andare a rappresentare.
        public DelegateCommand(Action<object> executeMethod, Predicate<object> canExecuteMethod)
        {
            this.executeMethod = executeMethod;
            this.canExecuteMethod = canExecuteMethod;
        }

        // Overloading del costruttore: qualora non venga passato il Predicate,
        // si assume che il comando sia sempre abilitato
        public DelegateCommand(Action<object> executeMethod)
        {
            this.executeMethod = executeMethod;
            this.canExecuteMethod = (o) => true;
        }

        // Restituisce un booleano che indica l'effettiva disponibilità del comando,
        // calcolato in base al metodo passato come parametro di ingresso nel costruttore
        public bool CanExecute(object parameter)
        {
            if (canExecuteMethod == null)
                return true;
            return canExecuteMethod(parameter);
        }

        // Invoca l'executeMethod che abbiamo passato come parametro di ingresso nel costruttore
        public void Execute(object parameter)
        {
            if (executeMethod == null)
                return;
            executeMethod(parameter);
        }

    }

}
